package com.elitel.conf;

import com.elitel.common.core.domain.SysUserInfo;
import com.elitel.common.utils.SysUserUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.beans.factory.annotation.Value;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Intercepts({
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {Connection.class, Integer.class}
        )
})
@Slf4j
public class AuditInterceptor implements Interceptor {

    static final String TENANT_ID = "tenantId";

    @Value("${isUseTenant}")
    private boolean isUseTenant;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler handler = (StatementHandler) invocation.getTarget();
        // 获取元数据对象
        MetaObject metaObject = SystemMetaObject.forObject(handler);
        BoundSql boundSql = handler.getBoundSql();
        String sql = boundSql.getSql();
        String lowerCase = sql.toLowerCase(Locale.ROOT).trim();

        SysUserInfo userInfo = SysUserUtils.getUserInfo();
        String tenantId = Optional.ofNullable(userInfo).map(SysUserInfo::getExtendProp)
                .map(prop -> prop.get(TENANT_ID)).map(Object::toString).orElse(null);
        String account = Optional.ofNullable(userInfo).map(SysUserInfo::getAccount).orElse(null);
        System.out.println("----------tenantId------------" + tenantId);
        System.out.println("----------account------------" + account);
//        if ("admin".equals(account)) {
//            tenantId = null;
//        }
        if (lowerCase.startsWith("select") || lowerCase.startsWith("with")) {
            if (sql.contains("###")) {
                Object obj = metaObject.getValue("boundSql");
                if (obj == null) throw new SQLException("boundSql is null");
                metaObject = SystemMetaObject.forObject(obj);
                if (tenantId != null && !tenantId.isEmpty() && isUseTenant) {
                    String newSql = sql.replace("###", " '" + tenantId + "' ");
                    metaObject.setValue("sql", newSql);
                } else {
                    List<String> allTenantId = getAllTenantId(sql);
                    for (String tid : allTenantId) {
                        if (!"tenant_id".equals(tid)) {
                            sql = sql.replace(tid + " = ###", " 2=2 ");
                        }
                    }
                    if (sql.contains("tenant_id = ###")) {
                        sql = sql.replace("tenant_id = ###", " 2=2 ");
                    }
                    String newSql = sql;
                    metaObject.setValue("sql", newSql);
                }
            }
        }

        if (lowerCase.startsWith("insert") && isUseTenant) {
            if (tenantId != null && !tenantId.isEmpty()) {
                Object obj = metaObject.getValue("boundSql");
                if (obj == null) throw new SQLException("boundSql is null");
                metaObject = SystemMetaObject.forObject(obj);
                String oldSql = metaObject.getValue("sql").toString();
                String[] split = oldSql.split("\\)");
                if (split.length < 2)
                    throw new SQLException("不支持insert into tb values(?,?)语法，请使用标准语法insert into tb (?,?) values(?,?)");
                split[0] += ",tenant_id)";
                String values = "";
                for (int i = 1; i < split.length; i++) {
                    split[i] += ",'" + tenantId + "')";
                    values += split[i];
                }
                values = values.substring(1);
                String newSql = split[0] + values;
                metaObject.setValue("sql", newSql);
            }
        }
        long start = System.currentTimeMillis();
        Object proceed = invocation.proceed();
        long end = System.currentTimeMillis();
        log.info("sql-time: {} ms", end - start);
        return proceed;
    }

    public static List<String> getAllTenantId(String sql) {
        Pattern pattern = Pattern.compile(
                "\\b([a-zA-Z_]\\w*)\\.tenant_id\\b|\\btenant_id\\b",
                Pattern.CASE_INSENSITIVE  // 忽略大小写
        );

        Matcher matcher = pattern.matcher(sql);
        List<String> list = new ArrayList<>();

        while (matcher.find()) {
            list.add(matcher.group());
        }
        return list;
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 可接收配置文件参数
    }
}